﻿using AForge.Imaging.Filters;
using Karbel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using Trimmer.Utility;

namespace Trimmer
{

    //public static class ListExtensions
    //{
    //    public static int BinarySearch<T, U>(this IList<T> tf, U target, Func<T, U> selector)
    //    {
    //        var lo = 0;
    //        var hi = (int)tf.Count - 1;
    //        var comp = Comparer<U>.Default;

    //        while (lo <= hi)
    //        {
    //            var median = lo + (hi - lo >> 1);
    //            var num = comp.Compare(selector(tf[median]), target);
    //            if (num == 0)
    //                return median;
    //            if (num < 0)
    //                lo = median + 1;
    //            else
    //                hi = median - 1;
    //        }

    //        return ~lo;
    //    }
    //}

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Graphics g;
        Bitmap bm, bmOrg;
        byte Sobel = 240;
        int Contrast = 50;
        float enlargement = 0.3F;
        private Point RectStartPoint;
        string id = string.Empty;
        string targetDirectory = @"D:\AksPhoto";
        string targetDirectoryR = @"D:\AksPhoto.rect";

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Visible = false;

            using (Login login = new Login())
            {
                DialogResult dr = login.ShowDialog();
                if (dr == DialogResult.OK)
                {
                    this.Visible = true;

                    AppSession appSession = new AppSession();
                    AppSession.DataManager = new DataManager(login.ConnectionString);
                }
                else
                    Application.Exit();
            }



            //textBox1.Text = contrastFactor.ToString();

            for (int i = 0; i < 255; i += 5)
                listBoxSobel.Items.Add(i);

            int index = listBoxSobel.FindString(Sobel.ToString());
            listBoxSobel.SetSelected(index, true);
            listBoxSobel.SelectedValueChanged += listBoxSobel_SelectedValueChanged;

            for (int i = 0; i < 100; i += 5)
                listBoxContrast.Items.Add(i);

            int index2 = listBoxContrast.FindString(Contrast.ToString());
            listBoxContrast.SetSelected(index2, true);
            listBoxContrast.SelectedValueChanged += listBoxContrast_SelectedValueChanged;

            btnSuz.Click += btnSuz_Click;
            btnAc.Click += btnAc_Click;
            checkBoxManuel.CheckedChanged += checkBoxManuel_CheckedChanged;
            btnSonraki.Click += btnSonraki_Click;
            btnOnceki.Click += btnOnceki_Click;

            btnKaydetVeSonraki.Click += btnKaydetVeSonraki_Click;
            btnSonrakiX.Click += btnSonrakiX_Click;
            btnOncekiX.Click += btnOncekiX_Click;
            
            this.MouseDown += Form1_MouseDown;
            this.MouseUp += Form1_MouseUp;

            //btnAc.PerformClick();

            GetStatus();
            Ac(GetFile(id, 1, 1));
        }

        void checkBoxManuel_CheckedChanged(object sender, EventArgs e)
        {
            listBoxContrast.Enabled = listBoxSobel.Enabled = !checkBoxManuel.Checked;
        }

        public string Kategori = "TÜMÜ";
        List<string> flt = new List<string>();
        void btnSuz_Click(object sender, EventArgs e)
        {
            string lstR = "0";
            foreach (KeyValuePair<string, Rectangle> p in listR)
                lstR += "," + p.Key;

            using (Suz suz = new Suz(string.Join(",", listF.ToArray()), lstR, Kategori))
            {
                if (suz.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Kategori = suz.Kategori;
                    this.Text = Kategori;

                    flt = new List<string>();
                    foreach (DataRow r in suz.dtSel.Rows)
                        flt.Add(r["Sira"].ToString());

                    Ac(GetFile("0", 1, 1));
                }

            }
        }

        void btnKaydetVeSonraki_Click(object sender, EventArgs e)
        {
            System.IO.File.WriteAllText(targetDirectoryR + "\\" + id + ".txt",
                rect4.X.ToString() + "," +
                rect4.Y.ToString() + "," +
                rect4.Width.ToString() + "," +
                rect4.Height.ToString());

            if (!listR.ContainsKey(id))
                listR.Add(id, rect4);
            else
                listR[id] = rect4;

            Ac(GetFile(id, 1, 1));
        }

        void btnOncekiX_Click(object sender, EventArgs e)
        {
            Ac(GetFile(id, -1, 1));
        }

        void btnSonrakiX_Click(object sender, EventArgs e)
        {
            Ac(GetFile(id, 1, 1));
        }

        void btnOnceki_Click(object sender, EventArgs e)
        {
            Ac(GetFile(id, -1));
        }

        void btnSonraki_Click(object sender, EventArgs e)
        {
            Ac(GetFile(id, 1));
        }

        int stage = 0;
        void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            RectStartPoint = new Point((int)(e.Location.X / enlargement), (int)(e.Location.Y / enlargement));
            stage = 1;
        }

        void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            if (stage > 0)
            {
                stage = 0;
                lookInside = new Rectangle(RectStartPoint, new Size((int)(e.Location.X / enlargement) - RectStartPoint.X, (int)(e.Location.Y / enlargement) - RectStartPoint.Y));
                Ciz();
            }
        }

        Dictionary<string, Rectangle> listR = new Dictionary<string, Rectangle>();
        List<string> listF = new List<string>();
        //List<string> listF1 = new List<string>();

        string GetFN(string fileName)
        {
            //return new FileInfo(fileName).Name;
            return System.IO.Path.GetFileNameWithoutExtension(fileName);
        }

        void GetStatus()
        {
            string[] fileEntries = Directory.GetFiles(targetDirectory);
            foreach (string fileName in fileEntries)
                listF.Add(GetFN(fileName));

            fileEntries = Directory.GetFiles(targetDirectoryR);
            foreach (string fileName in fileEntries)
                using (StreamReader reader = new StreamReader(fileName))
                {
                    string[] r = reader.ReadLine().Split(",".ToCharArray());
                    string id = GetFN(fileName);

                    listR.Add(id, new Rectangle(int.Parse(r[0]), int.Parse(r[1]), int.Parse(r[2]), int.Parse(r[3])));
                }

            listF.Sort();
        }

        string GetFile(string Cur, int yon, int Atla = 0)
        {
            //flt.Add("0");   //flt null olduğunda hata vermesin diye

            if (yon > 0)
                foreach (string str in listF)
                {
                    if (string.Compare(str, Cur) > 0)
                    {
                        if (flt.Count == 0 || flt.Contains(str))
                            if (Atla > 0)
                            {
                                if (listR.ContainsKey(str))
                                    continue;
                                else
                                    return targetDirectory + "\\" + str + ".JPG";
                            }
                            else
                                return targetDirectory + "\\" + str + ".JPG";
                    }
                }
            else
            {
                List<string> listFx = new List<string>(listF);
                listFx.Reverse();
                foreach (string str in listFx)
                {
                    if (string.Compare(str, Cur) < 0)
                    {
                        if (flt.Count == 0 || flt.Contains(str))
                            if (Atla > 0)
                            {
                                if (listR.ContainsKey(str))
                                    continue;
                                else
                                    return targetDirectory + "\\" + str + ".JPG";
                            }
                            else
                                return targetDirectory + "\\" + str + ".JPG";
                    }
                }
            }

            return string.Empty;
        }



        void listBoxSobel_SelectedValueChanged(object sender, EventArgs e)
        {
            Sobel = (byte)((int)listBoxSobel.SelectedItem);
            Ciz();
        }

        void listBoxContrast_SelectedValueChanged(object sender, EventArgs e)
        {
            bm = bmOrg.Clone() as Bitmap;
            Contrast = (byte)((int)listBoxContrast.SelectedItem);
            Ciz();
        }

        
        void btnAc_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog1 = new OpenFileDialog())
            {
                openFileDialog1.Filter = "All Files (*.*)|*.*";
                openFileDialog1.FilterIndex = 1;
                //openFileDialog1.Multiselect = true;

                if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    Ac(openFileDialog1.FileName);
            }
        }

        private void Ac(string fn)
        {
            if (fn != string.Empty)
            {
                GC.Collect();
                id = GetFN(fn);
                bm = new Bitmap(fn);
                bmOrg = new Bitmap(fn);
                lookInside = new Rectangle(10, 10, bm.Width - 20, bm.Height - 20);

                Ciz();
            }
        }

        Rectangle rect4;
        Rectangle lookInside;
        private void Ciz()
        {
            if (lookInside.Width + lookInside.Height > 10)
            {
                this.Text = Kategori + ". " + id;

                ContrastCorrection filter = new ContrastCorrection(checkBoxManuel.Checked ? 0: Contrast);
                filter.ApplyInPlace(bm);

                //Grayscale filter2 = new Grayscale(0.2125, 0.7154, 0.0721);
                //bm = filter2.Apply(bm);

                if (listR.ContainsKey(id) &&
                    lookInside == new Rectangle(10, 10, bm.Width - 20, bm.Height - 20))
                    rect4 = listR[id];
                else
                    rect4 = FindBoxSobel(bm, lookInside, (checkBoxManuel.Checked ? (byte)0 : Sobel));


                Graphics g = this.CreateGraphics();
                g.ScaleTransform(enlargement, enlargement);
                g.DrawImage(bmOrg, new Rectangle(0, 0, bmOrg.Width, bmOrg.Height));
                g.DrawRectangle(new Pen(Color.Red, 2), rect4);


                //Create a brush with an alpha value and use the g.FillRectangle function
                //Color customColor = Color.FromArgb(20, Color.Black);
                //SolidBrush shadowBrush = new SolidBrush(customColor);
                //g.FillRectangles(shadowBrush, new RectangleF[] { rect4 });


                //pictureBox1.Image = new Bitmap(bm);
                //image.Save( imageNewPath );


                //using (System.IO.StreamReader reader = new System.IO.StreamReader(fileStream))
                //{
                //    // Read the first line from the file and write it the textbox.
                //    //tbResults.Text = reader.ReadLine();
                //}
            }
        }


        public Rectangle FindBoxSobel(Bitmap originalImage, Rectangle lookInside, byte threshold)
        {

            Bitmap image = originalImage;
            try
            {
                //Convert if needed (makes an extra copy)
                if (image.PixelFormat != PixelFormat.Format24bppRgb &&
                    image.PixelFormat != PixelFormat.Format32bppArgb &&
                    image.PixelFormat != PixelFormat.Format32bppRgb)
                {
                    image = AForge.Imaging.Image.Clone(image, PixelFormat.Format24bppRgb);
                }

                //Crop if needed (makes an extra copy unless we converted too, then only 1 extra copy)
                if (!lookInside.Equals(new Rectangle(0, 0, image.Width, image.Height)))
                {
                    Bitmap oldImage = image;
                    try
                    {
                        image = new Crop(lookInside).Apply(image);
                    }
                    catch (Exception Ex)
                    {
                    }
                    finally
                    {
                        if (oldImage != originalImage) oldImage.Dispose(); //Dispose the cloned 
                    }
                }


                //Makes 1 more copy at 1/3rd the size, in grayscale
                Rectangle result = FindBoxSobel(image, threshold);
                return new Rectangle(lookInside.X + result.X, lookInside.Y + result.Y, result.Width, result.Height);


            }
            finally
            {
                if (image != originalImage) image.Dispose();
            }

        }

        public Rectangle FindBoxSobel(Bitmap rgb, byte threshold)
        {
            using (Bitmap gray = Grayscale.CommonAlgorithms.Y.Apply(rgb))
            {

                //Apply sobel operator to grayscale image
                new SobelEdgeDetector().ApplyInPlace(gray);
                //Threshold into black and white.
                new Threshold(threshold).ApplyInPlace(gray);
                //Trim only exact black pixels
                // lock source bitmap data
                BitmapData data = gray.LockBits(new Rectangle(0, 0, gray.Width, gray.Height), ImageLockMode.ReadOnly, gray.PixelFormat);
                try
                {
                    return FindBoxExactGrayscale(data, 0);
                }
                finally
                {
                    gray.UnlockBits(data);
                }
            }
        }

        public Rectangle FindBoxExactGrayscale(BitmapData sourceData, byte indexToRemove)
        {
            if (sourceData.PixelFormat != PixelFormat.Format8bppIndexed) throw new ArgumentOutOfRangeException("FindBoxExact only operates on 8-bit grayscale images");
            // get source image size
            int width = sourceData.Width;
            int height = sourceData.Height;
            int offset = sourceData.Stride - width;

            int minX = width;
            int minY = height;
            int maxX = 0;
            int maxY = 0;

            // find rectangle which contains something except color to remove
            unsafe
            {
                byte* src = (byte*)sourceData.Scan0;

                for (int y = 0; y < height; y++)
                {
                    if (y > 0) src += offset; //Don't adjust for offset until after first row
                    for (int x = 0; x < width; x++)
                    {
                        if (x > 0 || y > 0) src++; //Don't increment until after the first pixel.
                        if (*src != indexToRemove)
                        {
                            if (x < minX)
                                minX = x;
                            if (x > maxX)
                                maxX = x;
                            if (y < minY)
                                minY = y;
                            if (y > maxY)
                                maxY = y;
                        }
                    }
                }
            }

            // check
            if ((minX == width) && (minY == height) && (maxX == 0) && (maxY == 0))
            {
                minX = minY = 0;
            }

            return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
        }

        //        }

    }
}
